<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 2. 隐式调用规则  谁调用指向谁  
        // 注意：函数执行时才有this的指向，所以判断this指向时，要看执行环境，而不是调用环境
        let obj1 = {
            foo:function() {
                console.log(this)
            }
        }

        obj1.foo()

        // 下面this指向问题
        // 第二个：this指向window,test函数是独立调用，所以this指向window
        let obj2 = {
            foo:function() {
                console.log(this)  // obj2
                function test() {
                    console.log(this)  // ?
                }

                test()
            }
        }
        obj2.foo()

        // 立即调用函数指向 window,
        // 注意不管什么情况下，立即调用函数中的this都指向window,因为是函数的独立调用
        let obj3 = {
            foo:function() {
                // 立即调用函数
                (function(){
                    console.log(this)
                })()
            }
        }
        obj3.foo()

        // 闭包
        // 通俗定义：当函数执行的时候，导致函数被定义，并抛出，如下:
        let obj4 = {
            foo: function() {
                function test() {
                    console.log(this);
                }

                return test;
            }
        }

        obj4.foo()();
        //  上边this 指向window, 本质是函数的独立作用，可以转化为以下：
        let test =  obj4.foo()
        test()


        // 注意，判断this 时，要判断 调用方式，是独立调用还是 隐式调用
        // 变量赋值情况
        function foo() {
            console.log(this)
        }

        let obj5 = {
            foo:foo
        }

        obj5.foo();  // obj5

        // 这种情况实际叫：隐式丢失，在这里我们可以看成  独立调用 类型
        let bar = obj5.foo;
        bar()   // window

        // 参数方式
        function foo1() {
            console.log(this)
        }

        function bar1(fn) {
            fn()
        }

        let obj6 = {
            foo1:foo1
        }

        bar1(obj6.foo1)

        // 对于上边this指向，我们只需要看this 所在函数的调用方式即可
        // 首先看bar1指向时，接收参数：fn = obj6.foo1,  接着fn()独立调用 ，所以this-> window

        // 父函数是有能力决定子函数this指向的，将上边例子改一下
        function foo2() {
            console.log(this)
        }

        function bar2(fn) {
            // fn()
            // new fn();
            fn.call(obj7)
        }

        let obj7 = {
            foo2:foo2
        }

        bar2(obj7.foo2)

        // 可以看到 bar2的子函数fn  的指向，在bar2函数中是可以改变的，
        // 当我们调用js提供的接口时，比如数组的forEach,文档就会给出 传值去改变this问题
        // 同时在这里我们可以学习一个名词：回调函数，当给一个函数传递一个函数作为参数时，传递的函数就被称为 回调函数
        let arr = [1, 2, 3]
        arr.forEach(function(arr, item, index){
            console.log(this)
        })

    </script>
</body>
</html>